package com.mtiiot.fstcpserver.stat.nipstat;

import com.mtiiot.fstcpserver.base.BaseService;
import com.mtiiot.fscore.bean.MetadataInfo;
import com.mtiiot.fscore.bean.elasticsearch.nip.CancelStatResult;
import com.mtiiot.fscore.bean.elasticsearch.nip.CrisisTestStatResult;
import com.mtiiot.fscore.bean.elasticsearch.nip.DelayTestStatResult;
import com.mtiiot.fscore.inter1.NIPStatService1;
import com.mtiiot.fscore.utils.StringUtil;
import com.mtiiot.fstcpserver.es.BaseElasticsearch;
import com.mtiiot.fstcpserver.utils.Constants;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.Client;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.filter.InternalFilter;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.max.Max;
import org.elasticsearch.search.aggregations.metrics.sum.Sum;
import org.elasticsearch.search.aggregations.metrics.valuecount.ValueCount;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

/**
 * Created by lcy on 16-9-6.
 */
public class NipStatServiceImpl1 extends BaseService implements NIPStatService1 {
    private static final Logger logger = LogManager.getLogger(NipStatServiceImpl1.class);
    @Autowired
    private BaseElasticsearch baseElasticsearch;

    @Override
    public Map<String, Integer> getSpeSummaryData(MetadataInfo mi, String labId, String deptId, long startTime, long endTime) {
        Map<String, Integer> result = new HashMap<String, Integer>();
        Client client = null;
        try {
            //日志数据入队列
            checkMetadata(mi);//验证元数据
            client = baseElasticsearch.getEsDataSource().getClient();

            BoolQueryBuilder bq = QueryBuilders.boolQuery();
            if (!StringUtil.isEmpty(labId)) {
                bq.must(QueryBuilders.termQuery("laboratoryId", labId));                 // Query
            }
            if (!StringUtil.isEmpty(deptId)) {
                bq.must(QueryBuilders.termQuery("deptId", deptId));
            }

            //bq.must(QueryBuilders.termQuery("cusCode", "000123101"));//test yong  lcy

            // (测试)加上客户的ID.start
            //bq.must(QueryBuilders.termQuery("cusCode", "000123101"));
            //bq.must(QueryBuilders.termQuery("customerId", "40288ea5516aee5b01516af7c6330004"));
            // (测试)加上客户的ID.end

            bq.must(QueryBuilders.rangeQuery("receiveDate").from(startTime).to(endTime));
            QueryBuilder queryBuilder = bq;
            SearchRequestBuilder srb = client.prepareSearch(Constants.INDEX_NIP_PROCESS)
                    .setTypes(Constants.TYPE_NIP_PROCESS)
                            //按时间降序号
                            //.addSort("time", sortOrder)
                    .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                            // 设置查询数据的位置,分页用
                    .setFrom(0)
                            // 设置查询结果集的最大条数
                    .setSize(0)
                            // 设置是否按查询匹配度排序
                    .setExplain(true);
            /*// 最后就是返回搜索响应信息
            srb.setQuery(bq);
            //speCount(当前总标本量(子条码,sum)):实验室接收后的所有标本,即子条码状态为：[230，+)
            srb.addAggregation(AggregationBuilders.filter("f1").filter(QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("sdsStatus").gte(230)).must(QueryBuilders.existsQuery("subBarCode"))));
            //receiveNum:实验室接收到结果录入全部录入之前的(子条码,count)，即子条码状态为：[230，245)
            srb.addAggregation(AggregationBuilders.filter("f2").filter(QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("sdsStatus").gte(230).lt(245)).must(QueryBuilders.existsQuery("subBarCode"))));
            //resultInputNum(结果全部录入):子条码所以项目都录入了结果(子条码,count)，即子条码状态为：245,
            srb.addAggregation(AggregationBuilders.filter("f3").filter(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("sdsStatus", 245)).must(QueryBuilders.existsQuery("subBarCode"))));
            //submitNum(结果全部提交):子条码所以项目都提交(子条码,count)，即子条码状态为：255,
            srb.addAggregation(AggregationBuilders.filter("f4").filter(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("sdsStatus",255)).must(QueryBuilders.existsQuery("subBarCode"))));
            //auditNum(报告单全部审核):子条码所以项目都审核(子条码,count)，即子条码状态为：[265,+),
            srb.addAggregation(AggregationBuilders.filter("f5").filter(QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("sdsStatus").gte(265)).must(QueryBuilders.existsQuery("subBarCode"))));
            //warningNum(危急提示数量(项目,count)):按结果提示中有危急值提示累积统计，即ProcessNodeDto.tip like '★%',
            srb.addAggregation(AggregationBuilders.filter("f6").filter(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("tips", 1)).must(QueryBuilders.existsQuery("uniqueCode"))));
            */
            // 最后就是返回搜索响应信息

            // 2016.12.02,根据康源需求修改.
            // 按照子条码号分组统计
            srb.setQuery(bq);
            //speCount(当前总标本量(子条码,sum)):实验室接收后的所有标本,即子条码状态为：[230，+)
            srb.addAggregation(AggregationBuilders.filter("f1").filter(QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("sdsStatus").gte(230)).must(QueryBuilders.existsQuery("subBarCode"))).subAggregation(AggregationBuilders.terms("f1-1").field("subBarCode").size(10000)));
            //receiveNum:实验室接收到结果录入全部录入之前的(子条码,count)，即子条码状态为：[230，245)
            srb.addAggregation(AggregationBuilders.filter("f2").filter(QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("sdsStatus").gte(230).lt(245)).must(QueryBuilders.existsQuery("subBarCode"))).subAggregation(AggregationBuilders.terms("f2-1").field("subBarCode").size(10000)));
            //resultInputNum(结果全部录入):子条码所以项目都录入了结果(子条码,count)，即子条码状态为：245,
            srb.addAggregation(AggregationBuilders.filter("f3").filter(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("sdsStatus", 245)).must(QueryBuilders.existsQuery("subBarCode"))).subAggregation(AggregationBuilders.terms("f3-1").field("subBarCode").size(10000)));
            //submitNum(结果全部提交):子条码所以项目都提交(子条码,count)，即子条码状态为：255,
            srb.addAggregation(AggregationBuilders.filter("f4").filter(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("sdsStatus", 255)).must(QueryBuilders.existsQuery("subBarCode"))).subAggregation(AggregationBuilders.terms("f4-1").field("subBarCode").size(10000)));
            //auditNum(报告单全部审核):子条码所以项目都审核(子条码,count)，即子条码状态为：[265,+),
            //srb.addAggregation(AggregationBuilders.filter("f5").filter(QueryBuilders.boolQuery().must(QueryBuilders.rangeQuery("sdsStatus").gte(265)).must(QueryBuilders.existsQuery("subBarCode"))).subAggregation(AggregationBuilders.terms("f5-1").field("subBarCode").size(10000)));
            //auditNum(报告单全部审核):子条码所以项目都审核(子条码,count)，即子条码状态为：265, 2016/12/5 新改规则
            srb.addAggregation(AggregationBuilders.filter("f5").filter(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("sdsStatus", 265)).must(QueryBuilders.existsQuery("subBarCode"))).subAggregation(AggregationBuilders.terms("f5-1").field("subBarCode").size(10000)));

            //warningNum(危急提示数量(项目,count)):按结果提示中有危急值提示累积统计，即ProcessNodeDto.tip like '★%',
            srb.addAggregation(AggregationBuilders.filter("f6").filter(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("tips", 1)).must(QueryBuilders.existsQuery("uniqueCode"))).subAggregation(AggregationBuilders.count("f6-1").field("uniqueCode")));

            SearchResponse response = srb.execute().actionGet();
            Aggregations aggs = response.getAggregations();

            InternalFilter inf1 = aggs.get("f1");
            InternalFilter inf2 = aggs.get("f2");
            InternalFilter inf3 = aggs.get("f3");
            InternalFilter inf4 = aggs.get("f4");
            InternalFilter inf5 = aggs.get("f5");
            InternalFilter inf6 = aggs.get("f6");


            Terms t1 = inf1.getAggregations().get("f1-1");
            List<Terms.Bucket> list1 = t1.getBuckets();

            Terms t2 = inf2.getAggregations().get("f2-1");
            List<Terms.Bucket> list2 = t2.getBuckets();

            Terms t3 = inf3.getAggregations().get("f3-1");
            List<Terms.Bucket> list3 = t3.getBuckets();

            Terms t4 = inf4.getAggregations().get("f4-1");
            List<Terms.Bucket> list4 = t4.getBuckets();

            Terms t5 = inf5.getAggregations().get("f5-1");
            List<Terms.Bucket> list5 = t5.getBuckets();

            ValueCount t6 = inf6.getAggregations().get("f6-1");



            /*result.put("speCount", (int) inf1.getDocCount());
            result.put("receiveNum", (int) inf2.getDocCount());
            result.put("resultInputNum", (int) inf3.getDocCount());
            result.put("submitNum", (int) inf4.getDocCount());
            result.put("auditNum", (int) inf5.getDocCount());
            result.put("warningNum", (int) inf6.getDocCount());*/

            result.put("speCount", list1.size());
            result.put("receiveNum", list2.size());
            result.put("resultInputNum", list3.size());
            result.put("submitNum", list4.size());
            result.put("auditNum", list5.size());
            result.put("warningNum", (int)t6.getValue());

            // 只统计退单
            delayAndCancle(client, result, labId, deptId, startTime, endTime);
            // 统计迟发（2016。12.02.方法新增。处理迟发值）
            delay(client, result, labId, deptId, startTime, endTime);

            return result;
        } catch (Exception ex) {
            //异常信息 元数据入reids队列
            handleException(Constants.MODULE_STAT_NIP, "NipStatServiceImpl1", "getSpeSummaryData", ex, logger);
            return result;
        } finally {
            if (client != null) {
                try {
                    baseElasticsearch.getEsDataSource().releaseClient(client);
                } catch (Exception e) {
                    handleException(Constants.MODULE_STAT_NIP, "NipStatServiceImpl1", "getSpeSummaryData", e, logger);
                }
            }
        }
    }
    // 统计退单cancelNum
    private void delayAndCancle(Client client, Map<String, Integer> result, String labId, String deptId, long startTime, long endTime) throws Exception {
        BoolQueryBuilder bq = QueryBuilders.boolQuery();
        if (!StringUtil.isEmpty(labId)) {
            bq.must(QueryBuilders.termQuery("laboratoryId", labId));                 // Query
        }
        if (!StringUtil.isEmpty(deptId)) {
            bq.must(QueryBuilders.termQuery("deptId", deptId));
        }
        bq.must(QueryBuilders.rangeQuery("receiveDate").from(startTime).to(endTime));

        //bq.must(QueryBuilders.termQuery("customerId", "40288ea5516aee5b01516af7c6330004"));//test yong  lcy

        // 加上客户的ID 接口调试.start
        //bq.must(QueryBuilders.termQuery("cusCode", "000123101"));
        //bq.must(QueryBuilders.termQuery("customerId", "40288ea5516aee5b01516af7c6330004"));
        // 接口调试.end

        QueryBuilder queryBuilder = bq;
        SearchRequestBuilder srb = client.prepareSearch(Constants.INDEX_NIP_EXCEPTION)
                .setTypes(Constants.TYPE_NIP_EXCEPTION)
                        //按时间降序号
                        //.addSort("time", sortOrder)
                .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                        // 设置查询数据的位置,分页用
                .setFrom(0)
                        // 设置查询结果集的最大条数
                .setSize(0)
                        // 设置是否按查询匹配度排序
                .setExplain(true);
        // 最后就是返回搜索响应信息
        srb.setQuery(bq);
        //delayNum(迟发数量 (项目算,count)):按迟发项目的个数累积统计,即ExceptionNodeDto.exceptionType=DELAY,
        //srb.addAggregation(AggregationBuilders.filter("f1").filter(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("exceptionType", "DELAY")).must(QueryBuilders.existsQuery("uniqueCode"))));
        //cancelNum(退单数量(母条码,count)):按退单母条码个数统计,即ExceptionNodeDto.exceptionType=CANCEL,
        srb.addAggregation(AggregationBuilders.filter("f2").filter(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("exceptionType", "CANCEL")).must(QueryBuilders.existsQuery("specimenId"))).subAggregation(AggregationBuilders.terms("f2-1").field("specimenId").subAggregation(AggregationBuilders.max("f2-1-1").field("delayNum"))));
        SearchResponse response = srb.execute().actionGet();
        Aggregations aggs = response.getAggregations();


        //InternalFilter inf1 = aggs.get("f1");
        //result.put("delayNum", (int)inf1.getDocCount());
        InternalFilter inf2 = aggs.get("f2");
        Terms terms=inf2.getAggregations().get("f2-1");
        List<Terms.Bucket> list = terms.getBuckets();
        int SumCount=0;
        for (Terms.Bucket tb : list) {
            Aggregations statsAggr = tb.getAggregations();
            Max max=statsAggr.get("f2-1-1");
            SumCount+=max.getValue();
        }


        result.put("cancelNum",SumCount);
    }
    // 查询迟发的值
    // 2016.12.02.康源需求（将每个文档的delayNum值取出做相加）
    private void delay(Client client, Map<String, Integer> result, String labId, String deptId, long startTime, long endTime) throws Exception {
        BoolQueryBuilder bq = QueryBuilders.boolQuery();
        if (!StringUtil.isEmpty(labId)) {
            bq.must(QueryBuilders.termQuery("laboratoryId", labId));                 // Query
        }
        if (!StringUtil.isEmpty(deptId)) {
            bq.must(QueryBuilders.termQuery("deptId", deptId));
        }
        bq.must(QueryBuilders.rangeQuery("receiveDate").from(startTime).to(endTime));
        bq.must(QueryBuilders.termQuery("exceptionType", "DELAY"));
        bq.must(QueryBuilders.existsQuery("uniqueCode"));

        //bq.must(QueryBuilders.termQuery("customerId", "40288ea5516aee5b01516af7c6330004"));//test yong  lcy

        SearchRequestBuilder srb = client.prepareSearch(Constants.INDEX_NIP_EXCEPTION)
                .setTypes(Constants.TYPE_NIP_EXCEPTION)
                        //按时间降序号
                        //.addSort("time", sortOrder)
                .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                        // 设置查询数据的位置,分页用
                .setFrom(0)
                        // 设置查询结果集的最大条数
                .setSize(0)
                        // 设置是否按查询匹配度排序
                .setExplain(true);
        // 最后就是返回搜索响应信息
        srb.setQuery(bq);
        srb.addAggregation(AggregationBuilders.sum("a-sum").field("delayNum"));
        SearchResponse response = srb.execute().actionGet();
        Aggregations sysAggr = response.getAggregations();
        Sum sum=sysAggr.get("a-sum");
        int delayNum = (int)sum.getValue();

//        SearchHits searchHits = response.getHits();
//        SearchHit[] hits = searchHits.getHits();
//
//        int delayNum = 0;
//        for (SearchHit searchHit : hits) {
//            Map<String, Object> sm = searchHit.sourceAsMap();
//            String num = sm.get("delayNum").toString();
//            delayNum = delayNum + Integer.parseInt(num);
//        }
        result.put("delayNum",delayNum );
    }


    @Override
    public Map<String, List> getSpedetailData(MetadataInfo mi, String labId, String deptId, long startTime, long endTime) {
        Map<String, List> result = new HashMap<String, List>();
        Client client = null;
        try {
            //日志数据入队列
            checkMetadata(mi);//验证元数据
            client = baseElasticsearch.getEsDataSource().getClient();


            BoolQueryBuilder bq = QueryBuilders.boolQuery();
            if (!StringUtil.isEmpty(labId)) {
                bq.must(QueryBuilders.termQuery("laboratoryId", labId));                 // Query
            }
            if (!StringUtil.isEmpty(deptId)) {
                bq.must(QueryBuilders.termQuery("deptId", deptId));
            }

            //bq.must(QueryBuilders.termQuery("customerId", "40288ea5516aee5b01516af7c6330004"));//test yong  lcy

            bq.must(QueryBuilders.rangeQuery("receiveDate").from(startTime).to(endTime));
            QueryBuilder queryBuilder = bq;
            SearchRequestBuilder srb = client.prepareSearch(Constants.INDEX_NIP_EXCEPTION)
                    .setTypes(Constants.TYPE_NIP_EXCEPTION)
                            //按时间降序号
                            //.addSort("time", sortOrder)
                    .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                            // 设置查询数据的位置,分页用
                    .setFrom(0)
                            // 设置查询结果集的最大条数
                    .setSize(0)
                            // 设置是否按查询匹配度排序
                    .setExplain(true);
            // 最后就是返回搜索响应信息
            srb.setQuery(bq);
            //迟发统计  项目 /数量
            srb.addAggregation(AggregationBuilders.filter("f1").filter(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("exceptionType", "DELAY")).must(QueryBuilders.existsQuery("uniqueCode"))).subAggregation(AggregationBuilders.terms("f1-1").field("uniqueCode").subAggregation(AggregationBuilders.sum("f1-1-1").field("delayNum"))));
            srb.addAggregation(AggregationBuilders.filter("f2").filter(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("exceptionType", "CANCEL")).must(QueryBuilders.existsQuery("barcode"))).subAggregation(AggregationBuilders.terms("f2-1").field("customerName").subAggregation(AggregationBuilders.terms("f2-1-1").field("barcode"))));
            //退单统计统计  客户/条码/数量
            SearchResponse response = srb.execute().actionGet();
            Aggregations aggs = response.getAggregations();

            List<DelayTestStatResult> rList1 = new ArrayList<DelayTestStatResult>();
            DelayTestStatResult result1 = null;

            InternalFilter inf1 = aggs.get("f1");
            Terms t1 = inf1.getAggregations().get("f1-1");
            List<Terms.Bucket> list = t1.getBuckets();
            for (Terms.Bucket tb : list) {
                result1 = new DelayTestStatResult();
                String uniqueCode = tb.getKey().toString();

                Sum sum=tb.getAggregations().get("f1-1-1");
                result1.setUniqueCode(uniqueCode);
//                long doc = tb.getDocCount();
//                result1.setCount(doc);
                result1.setCount((long)sum.getValue());
                rList1.add(result1);
            }
            result.put("delay", rList1);

            List<CancelStatResult> rList2 = new ArrayList<CancelStatResult>();
            CancelStatResult result2 = null;

            InternalFilter inf2 = aggs.get("f2");
            Terms t2 = inf2.getAggregations().get("f2-1");
            List<Terms.Bucket> list2 = t2.getBuckets();
            for (Terms.Bucket tb : list2) {
                String customerName = tb.getKey().toString();
                Terms t21 = tb.getAggregations().get("f2-1-1");
                List<Terms.Bucket> list21 = t21.getBuckets();
                for (Terms.Bucket tb2 : list21) {
                    result2 = new CancelStatResult();
                    result2.setCustomerName(customerName);
                    String barcode = tb2.getKey().toString();
                    result2.setBarcode(barcode);
                    long doc = tb2.getDocCount();
                    result2.setCount(doc);
                    rList2.add(result2);
                }
            }
            result.put("cancel", rList2);
            statdelayAndCancle(client, result, labId, deptId, startTime, endTime);

            return result;
        } catch (Exception ex) {
            //异常信息 元数据入reids队列
            handleException(Constants.MODULE_STAT_NIP, "NipStatServiceImpl1", "getSpedetailData", ex, logger);
            return result;
        } finally {
            if (client != null) {
                try {
                    baseElasticsearch.getEsDataSource().releaseClient(client);
                } catch (Exception e) {
                    handleException(Constants.MODULE_STAT_NIP, "NipStatServiceImpl1", "getSpedetailData", e, logger);
                }
            }
        }
    }


    private void statdelayAndCancle(Client client, Map<String, List> result, String labId, String deptId, long startTime, long endTime) throws Exception {

        BoolQueryBuilder bq = QueryBuilders.boolQuery();
        if (!StringUtil.isEmpty(labId)) {
            bq.must(QueryBuilders.termQuery("laboratoryId", labId));                 // Query
        }
        if (!StringUtil.isEmpty(deptId)) {
            bq.must(QueryBuilders.termQuery("deptId", deptId));
        }

        //bq.must(QueryBuilders.termQuery("cusCode", "000123101"));//test yong  lcy

        bq.must(QueryBuilders.rangeQuery("receiveDate").from(startTime).to(endTime));
        QueryBuilder queryBuilder = bq;
        SearchRequestBuilder srb = client.prepareSearch(Constants.INDEX_NIP_PROCESS)
                .setTypes(Constants.TYPE_NIP_PROCESS)
                        //按时间降序号
                        //.addSort("time", sortOrder)
                .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                        // 设置查询数据的位置,分页用
                .setFrom(0)
                        // 设置查询结果集的最大条数
                .setSize(0)
                        // 设置是否按查询匹配度排序
                .setExplain(true);
        // 最后就是返回搜索响应信息
        srb.setQuery(bq);
        //warningNum(危急提示数量(项目,count)):按结果提示中有危急值提示累积统计，即ProcessNodeDto.tip like '★%',
        srb.addAggregation(AggregationBuilders.filter("f1").filter(QueryBuilders.boolQuery().must(QueryBuilders.termQuery("tips", 1)).must(QueryBuilders.existsQuery("uniqueCode"))).subAggregation(AggregationBuilders.terms("f1-1").field("uniqueCode")));


        SearchResponse response = srb.execute().actionGet();
        Aggregations aggs = response.getAggregations();
        InternalFilter inf1 = aggs.get("f1");
        Terms t1 = inf1.getAggregations().get("f1-1");
        List<Terms.Bucket> list = t1.getBuckets();
        List<CrisisTestStatResult> rList1 = new ArrayList<CrisisTestStatResult>();
        CrisisTestStatResult result1 = null;
        for (Terms.Bucket tb : list) {
            result1 = new CrisisTestStatResult();
            String uniqueCode = tb.getKey().toString();
            result1.setUniqueCode(uniqueCode);
            long doc = tb.getDocCount();
            result1.setCount(doc);
            rList1.add(result1);
        }
        result.put("warning", rList1);
    }
}
